package controlador;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import javax.swing.JCheckBox;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import controlador.excepciones.FuncionNoEncontrada;

import vista.VistaLista;

import modelo.Modelo;
import modelo.Observado;
import modelo.Observador;
import modelo.abstraccionesGeometricas.Punto;
import modelo.funciones.Funcion;

public class AdministradorDeEvaluaciones implements ActionListener,ListSelectionListener,Observado{
	
	private boolean recalcular;
	private List<Observador> lista;
	private List<Funcion> funciones;
	private List<List<Punto>> puntos;
	private Modelo modelo;
	private ManejadorDeES manejador;
	private Evaluador evaluador;
	
	public AdministradorDeEvaluaciones(Modelo modelo){
		this.modelo=modelo;
		this.setFunciones(new ArrayList<Funcion>());
		this.lista=new ArrayList<Observador>();
		this.puntos=new ArrayList<List<Punto>>();
		this.setManejador(ManejadorDeES.getInstancia());
		this.evaluador=new Evaluador();
		this.setRecalcular(true);
	}
	
	private void setRecalcular(boolean bandera){
		this.recalcular=bandera;
	}
	
	private boolean hayQueRecalcular(){
		return this.recalcular;
	}
	
	private Modelo getModelo(){
		return this.modelo;
	}
	
	public void setPuntos(List<List<Punto>> puntos){
		this.puntos=puntos;
	}
	
	public List<List<Punto>> getPuntos(){
		return this.puntos;
	}  
	
	public void setFunciones(List<Funcion> f){
		this.funciones=f;
	}
	
	public List<Funcion> getFunciones(){
		return this.funciones;
	} 
	
	public void setManejador(ManejadorDeES manejador){
		this.manejador=manejador;
	}
	
	public ManejadorDeES getManejador(){
		return this.manejador;
	}  
	
	public void actionPerformed(ActionEvent arg0) {
		JCheckBox checkBox=(JCheckBox)arg0.getSource();
		if (checkBox.isSelected()) this.setRecalcular(false);
		else this.setRecalcular(true);
	}
	
	/*
	 * post: carga su lista de funciones con las funciones que
	 * debe evaluar
	 */
	private void actualizarListaFunciones(ListSelectionEvent arg0){
		if (!this.getModelo().getFunciones().isEmpty()){
			this.getFunciones().clear();
			VistaLista vistaLista=(VistaLista)arg0.getSource();
			int []vector=vistaLista.getSelectedIndices();
			for (int i=0;i<vector.length;i++)
			this.getFunciones().add((Funcion)this.getModelo().getFunciones().get(vector[i]));
			}
	}
	
	private void recalcular(Funcion f){
		this.getPuntos().add(this.evaluador.evaluarFuncion(f));
	}
	
	/*
	 * post: crea un xml con los resultados de la evaluacion de la funcion
	 */
	private void cargarFuncion(Funcion f){
		List<Punto> puntos=this.evaluador.evaluarFuncion(f);
		this.getPuntos().add(puntos);
		try {
			this.getManejador().guardarEnXML(puntos, f);
		} catch (IOException e){}
	}
	
	/*
	 * post: toma los puntos de la base de datos, en caso de que
	 * no se encuentren evalua y carga en la base de datos
	 */
	private void resultadosBaseDeDatos(Funcion f){
		try{
			this.getPuntos().add(this.getManejador().cargarDesdeXML(f));
		} catch (FuncionNoEncontrada e){
			this.cargarFuncion(f);
		} catch (IOException e){
			this.cargarFuncion(f);
		}
	}
	
	/*
	 * post: carga su lista de lista de puntos evaluados y luego le
	 * avisa a la vistaGraficador que grafique usando los puntos 
	 * que este ya evaluo
	 * (non-Javadoc)
	 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
	 */
	public void valueChanged(ListSelectionEvent arg0) {
		this.actualizarListaFunciones(arg0);
		this.getPuntos().clear();
		ListIterator iterador=this.getFunciones().listIterator();
		while (iterador.hasNext()){
			Funcion f=(Funcion)iterador.next();
			if (this.hayQueRecalcular()) this.recalcular(f);
			else resultadosBaseDeDatos(f);
		}
		this.cambie();
	}

	public void cambie()
	{
		ListIterator<Observador> iterador= lista.listIterator();
		while (iterador.hasNext()){
			Observador obs=iterador.next();
			obs.update(this);
		}
	}

	public void agregarObservador(Observador obs) {
		lista.add(obs);
	}

	public void sacarObservador(Observador obs) {
		lista.remove(obs);	
	}

}
